<?php

  /**
   * Record
   *
   * Базовый класс для всех ORM
   *
   * @property-read WebApplication $app ссылка на экземпляр приложения
   */

  abstract class Record extends CActiveRecord
  {
    /**
     * вернуть имя таблицы
     *
     * @return string
     * @access public
     */
    public function tableName()
    {
      return mb_strtolower(parent::tableName())."s";
    }

    /**
     * создать запись в таблице
     *
     * @param array $attributes    значения полей
     * @param bool  $runValidation проверить перед сохранением
     * @return mixed (primary key или null)
     * @access public
     */
    public function createRecord(array $attributes, $runValidation = true)
    {
      $this->isNewRecord = true;
      $this->attributes  = $attributes;
      return $this->save($runValidation) ? $this->primaryKey : null;
    }

    /**
     * вернуть возможные значения поля типа enum или set
     *
     * @param string $field имя поля
     * @param string $type  тип поля
     * @return string[]
     * @access public
     */
    public function enum($field, $type = "enum")
    {
      return array_filter(
        preg_split("/($type\('|','|'\))/u", $this->tableSchema->columns[$field]->dbType),
        create_function('$v', 'return !!$v;')
      );
    }

    /**
     * параметры выборки для различных значений поля типа enum
     *
     * @param string $field имя поля
     * @return array[]
     * @access protected
     */
    protected function enumScopes($field)
    {
      $scopes = array();

      if ($this->hasAttribute($field))
        foreach ($this->enum($field) as $value)
          $scopes[$value] = array("condition" => "`$field`='$value'");

      return $scopes;
    }

    /**
     * вернуть размер поля
     *
     * @param string $field имя поля
     * @return int
     * @access public
     */
    public function fieldSize($field)
    {
      return $this->tableSchema->columns[$field]->size;
    }

    /**
     * ссылка на экземпляр приложения
     *
     * @return WebApplication
     * @access public
     */
    public function getApp()
    {
      return Yii::app();
    }

    /**
     * скорректировать присланный HTML-код
     *
     * @param string $html html-код
     * @param bool   $fill заполнить, если текста нет
     * @return string
     * @access public
     */
    public static function validHTML($html, $fill = true)
    {
      if ($html !== null)
      {
        if ($html)
        {
        // заменяем лишние пробелы на один
          $html = preg_replace("/\s+/u", " ", trim($html));
        // удаляем разрывы строк и теги из внешнего пространства имен
          $html = preg_replace("/<\/?(wbr|[a-z]+:[a-z]+)(\s+.*?)?\/?>/ui", "", $html);
        // закрываем незакрытые теги
          $html = preg_replace_callback("/<(br|hr|img)(\s+.*?)?>/ui", create_function('array $m', 'return "<$m[1]".rtrim($m[2], " /")." />";'), $html);
          $s    = preg_replace("/<\/(br|hr|img)(\s+.*?)?>/ui", "", $html);
          $html = "";
          $tags = array();
          $l    = strlen($s) - 1;
          $i    = 0;
          while ($i <= $l)
            if ($s{$i} == "<")
            {
              $j = $i;
              while ((++$j <= $l) && ($s{$j} != ">"));
              if (($i < $j) && ($j <= $l))
              {
                if ($s{$i + 1} == "/")
                {
                  $ctag = preg_replace("/^([a-z]+)(\s+.*)?$/ui", "$1", trim(substr($s, $i + 2, $j - $i - 2)));
                  do
                  {
                    $tag = array_pop($tags);
                    if ($ne = $tag && strcasecmp($tag, $ctag))
                      $html .= "</$tag>";
                  } while ($ne);
                  if (!$tag)
                    $html = "<$ctag>$html";
                }
                else
                  if ($s{$j - 1} != "/")
                    $tags[] = preg_replace("/^([a-z]+)(\s+.*)?$/ui", "$1", trim(substr($s, $i + 1, $j - $i - 1)));
                $html .= substr($s, $i, $j - $i + 1);
              }
              $i = $j + 1;
            }
            else
              $html .= $s{$i++};
        // удаляем скрипты
          $html = preg_replace("/<script(\s+.*?)?\/(script)?>/ui", "", $html);
        }
        if ($fill)
        {
          if (!$html)
            $html = "&nbsp;";
        // если текст не заключен в теги, оформляем как абзац
          if (!preg_match("/^<.*>$/u", $html))
            $html = CHtml::tag("p", array("encode" => false), $html);
        }
        else
          if (!preg_replace("/<br \/>/ui", "", $html))
            $html = null;
      }

      return $html;
    }
  }

?>
